如果把繼承也算上去的話,今天就是第六天的類別介紹了,在把類別講得更完整吧!
還記得在 DAY 10 隨口提到的類別的基底類別是 object,所以我們自己做的類別,實作後也都有 object 的方法,但由於我們沒有在再定義內容,所以有些方法可能不能用,或者不如預期,所以今天來把這些方法弄完整。
那我們來做一個座標類別示範
class Coordinate {
public Coordinate (decimal longitude, decimal latitude) {
this.longitude = longitude;
this.latitude = latitude;
}
public decimal longitude { get; }
public decimal latitude { get; }
}
Coordinate c1 = new Coordinate (12.156m, 7.195m);
Console.WriteLine (c1);
Console.ReadKey ();
可以看到顯示的是demo.Program+Coordinate
,因為我的命名空間是 demo,所以每個人看到的可能不一樣,但這資訊都是對我們沒有幫助的,我們希望印出的內容應該要能正確地獲得類別相關資訊,所以我們要
public override string ToString () {
return $"longitude: {longitude}, latitude: {latitude}";
}
因為 Console.WriteLine() 方法會呼叫對象的 ToString() 方法,而 object.ToString() 預設輸出類別名稱,就會發生印出不需要的內容,所以把 ToString 改成是轉出我們的相關成員的字串,之後印出這個類別就能得到有用的資訊。
因為做比較時 Equals() 會警告你需先重寫 GetHashCode(),不寫不會讓程式編譯失敗,但寫好程式的幾個要點之一就是,程式執行後不要有任何的警告。
public override int GetHashCode () {
int hashCode = longitude.GetHashCode ();
if (longitude.GetHashCode () != latitude.GetHashCode ()) {
hashCode ^= latitude.GetHashCode ();
}
return hashCode;
}
簡單來說,只要經緯度一樣,我們就得到的 HashCode 就會是一樣,至於為什麼要用 xor(^) 來操作,因為如果是以相加減來說,較容易出現不同經緯而數值一樣的狀況,但使用 and 容易變成全是 0,or 容易全是 1,所以通常都是用 xor 來做 HashCode 的處理。
有了 GetHashCode 後,我們就可以來比較類別了。
假設我們希望兩個物件只要內容一樣就表示相等,即便參考位置不一樣
Coordinate c1 = new Coordinate (12.156m, 7.195m);
Coordinate c2 = c1;
Coordinate c3 = new Coordinate (12.156m, 7.195m);
if (Coordinate.ReferenceEquals (c1, c2)) {
Console.WriteLine ("c1 與 c2 參考位置相等");
}
if (c1.Equals (c2)) {
Console.WriteLine ("c1 與 c2 相等");
}
if (Coordinate.ReferenceEquals (c1, c3)) {
Console.WriteLine ("c1 與 c3 參考位置相等");
}
if (c1.Equals (c3)) {
Console.WriteLine ("c1 與 c3 相等");
}
Console.ReadKey ();
可以看到 c1 一個也不跟 c3 相等,但我們希望 Equals() 時,顯示是 true,所以我們來改寫吧
public override bool Equals (object obj) {
if (obj == null)
return false;
if (this.GetType () != obj.GetType ())
return false;
return this.GetHashCode () == obj.GetHashCode ();
}
首先檢查 obj 是不是 null,再檢查型別一不一樣,然後就是用我們上面做過的方法,來確認值一不一樣。
但很多人可能使用 ==
來比較多過於使用 Equals(),但你會發現 (c1 == c3)
為 false ,所以我們要來重寫運算子。
我們就把==
做成跟我們 Equals() 一樣,不管參考位置
public static bool operator == (Coordinate c1, Coordinate c2) {
return c1.Equals (c2);
}
public static bool operator != (Coordinate c1, Coordinate c2) {
return !c1.Equals (c2);
}
因為重寫 ==
需要連同 !=
一起重寫,這樣我們就可以使用 ==
來做比較了。
再來就是加減的時候,能夠把經緯度相加減。
public static Coordinate operator + (Coordinate c1, Coordinate c2) {
return new Coordinate (c1.longitude + c2.longitude, c1.latitude + c2.latitude);
}
public static Coordinate operator - (Coordinate c1, Coordinate c2) {
return new Coordinate (c1.longitude - c2.longitude, c1.latitude - c2.latitude);
}
相加減後會傳回一個新的座標類別
Coordinate c1 = new Coordinate (12.156m, 7.195m);
Coordinate c2 = new Coordinate (12.06m, 1.516m);
Console.WriteLine (c1 + c2);
Console.ReadKey ();
今天只重寫了我覺得比較常用到的部分,還有很多很多的運算子可以重寫,就請大家自己練習了,最後附上這次完整的範例類別程式碼。
class Coordinate {
public Coordinate (decimal longitude, decimal latitude) {
this.longitude = longitude;
this.latitude = latitude;
}
public decimal longitude { get; }
public decimal latitude { get; }
public override string ToString () {
return $"longitude: {longitude}, latitude: {latitude}";
}
public override int GetHashCode () {
int hashCode = longitude.GetHashCode ();
if (longitude.GetHashCode () != latitude.GetHashCode ()) {
hashCode ^= latitude.GetHashCode ();
}
return hashCode;
}
public override bool Equals (object obj) {
if (obj == null)
return false;
if (this.GetType () != obj.GetType ())
return false;
return this.GetHashCode () == obj.GetHashCode ();
}
public static bool operator == (Coordinate c1, Coordinate c2) {
return c1.Equals (c2);
}
public static bool operator != (Coordinate c1, Coordinate c2) {
return !c1.Equals (c2);
}
public static Coordinate operator + (Coordinate c1, Coordinate c2) {
return new Coordinate (c1.longitude + c2.longitude, c1.latitude + c2.latitude);
}
public static Coordinate operator - (Coordinate c1, Coordinate c2) {
return new Coordinate (c1.longitude - c2.longitude, c1.latitude - c2.latitude);
}
}
感謝閱讀。